package com.leyou.item.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.leyou.common.dto.PageDTO;
import com.leyou.common.exception.LyException;
import com.leyou.item.dto.SkuDTO;
import com.leyou.item.dto.SpuDTO;
import com.leyou.item.dto.SpuDetailDTO;
import com.leyou.item.entity.*;
import com.leyou.item.mapper.SpuMapper;
import com.leyou.item.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static com.leyou.common.constants.MQConstants.*;

@Service
@Slf4j
public class SpuServiceImpl extends ServiceImpl<SpuMapper, Spu> implements SpuService {

    @Resource
    private BrandService brandService;

    @Resource
    private CategoryService categoryService;

    @Resource
    private SpuDetailService spuDetailService;

    @Resource
    private SkuService skuService;

    @Resource
    private RabbitTemplate rabbitTemplate;

    @Resource
    private AmqpTemplate amqpTemplate;

    @Override
    public PageDTO<SpuDTO> querySpuByPage(Long brandId, Long categoryId, Long id, Long page, Long rows, Boolean saleable) {

        //先分页查询spu,并且整合动态sql查询
        Page<Spu> pageInfo = new Page<>(page, rows);
        //动态sql，只有condition为true，自定义查询才会生效
        // 2.准备查询条件， SELECT * FROM tb_spu WHERE saleable = ? AND category_id = ? AND brand_id = ? AND id = ?
        this.query()
                .eq(brandId != null, "brand_id", brandId)
                .eq(categoryId != null, "cid3", categoryId)
                .eq(id != null, "id", id)
                .eq(saleable != null, "saleable", saleable)
                .page(pageInfo);

        // 3.封装结果
        List<SpuDTO> spuDTOs = SpuDTO.convertEntityList(pageInfo.getRecords());

        //TODO stream流写法
        //循环给dto赋值，brandName以及categoryName
//        spuDTOs.forEach(spuDTO -> {
//            spuDTO.setBrandName(this.brandService.getById(spuDTO.getBrandId()).getName());
//            //TODO 考虑缓存问题，
//            //根据分类的id集合查询分类集合，并取出每个分类的名称，并拼接字符串
//            String names = this.categoryService.listByIds(spuDTO.getCategoryIds())
//                    .stream().map(Category::getName)
//                    .collect(Collectors.joining("/"));
//            //StringUtils.join(array,分隔符)
//            spuDTO.setCategoryName(names);
//        });
        for (SpuDTO spuDTO : spuDTOs) {
            // 查询spu的分类和品牌的名称
            handleCategoryAndBrandName(spuDTO);
        }
        return new PageDTO<>(pageInfo.getTotal(),pageInfo.getPages(),spuDTOs);
    }

    @Override
    @Transactional
    public void saveGoods(SpuDTO spuDTO) {

        if (CollectionUtils.isEmpty(spuDTO.getSkus())){
            throw new LyException(400,"商品详情信息sku不能为空！");
        }

        // 1.新增/修改Spu 并主键回显
        Spu spu = spuDTO.toEntity(Spu.class);
        this.save(spu);
        log.info("保存spu成功");

        //2.新增商品详情SpuDetail
        SpuDetail spuDetail = spuDTO.getSpuDetail().toEntity(SpuDetail.class);
        //手动指派spuid  @TableId(type = IdType.INPUT)
        spuDetail.setSpuId(spu.getId());
        spuDetailService.save(spuDetail);
        log.info("保存SpuDetail成功");

        // 3.新增Sku
        //获取到是skuDTO集合，转为sku的集合，并且给每个sku设置spu_id以及saleable为true
        List<Sku> skuList = new ArrayList<>();
        List<SkuDTO> skuDTOs = spuDTO.getSkus();
        for (SkuDTO skuDTO : skuDTOs) {
            Sku sku = skuDTO.toEntity(Sku.class);
            //要跟spu的saleable（默认为1） 同步
            sku.setSaleable(true);
            sku.setSpuId(spu.getId());
            skuList.add(sku);
        }
        //TODO stream流写法
//        List<Sku> skuList1 = spuDTO.getSkus().stream().map(skuDTO -> {
//            Sku sku = skuDTO.toEntity(Sku.class);
//            sku.setSpuId(spu.getId());
//            sku.setSaleable(true);
//            return sku;
//        }).collect(Collectors.toList());
        skuService.saveBatch(skuList);
        log.info("批量保存Sku成功");
    }

    @Override
    @Transactional
    public void updateSpuSaleable(Long id, Boolean saleable) {
        //1.更新spu  update tb_spu set saleable = false where id = #{}
        Spu updateSpu = new Spu();
        updateSpu.setId(id);
        updateSpu.setSaleable(saleable);
        this.updateById(updateSpu);
        log.info("更新spu成功");

        //2.更新sku  update tb_sku set saleable = false where sup_id = #{}
//        skuService.update()
//                .eq("spu_id", id)
//                .set("saleable",saleable)
//                .update();
        log.info("更新sku成功");
        //第二种写法
        Sku sku = new Sku();
        sku.setSaleable(saleable);
        skuService.update(sku,new QueryWrapper<Sku>().eq("spu_id",id));

        // 3.发送MQ消息  交换机，rountingkey,id
        String routingKey = saleable ? RoutingKeyConstants.ITEM_UP_KEY : RoutingKeyConstants.ITEM_DOWN_KEY;
        amqpTemplate.convertAndSend(ExchangeConstants.ITEM_EXCHANGE_NAME, routingKey, id);
    }

    @Override
    @Transactional
    public void updateGoods(SpuDTO spuDTO) {
        //1.修改spu
        // 1.1.判断是否存在spu的id，有说明需要修改，没有说明不需要
        if(null != spuDTO.getId()){
            Spu spu = spuDTO.toEntity(Spu.class);
            this.updateById(spu);
        }

        //2.修改spuDetail
        SpuDetailDTO spuDetailDTO = spuDTO.getSpuDetail();
        if (null != spuDetailDTO && spuDetailDTO.getSpuId() != null){
            SpuDetail spuDetail = spuDetailDTO.toEntity(SpuDetail.class);
            spuDetailService.updateById(spuDetail);
        }
        //3.修改sku
        List<SkuDTO> skuDTOList = spuDTO.getSkus();
        // 3.1.判断是否包含sku
        if (CollectionUtils.isEmpty(skuDTOList)){
            return;
        }

        // 3.2.转换DTO，并将sku根据saleable是否为null来分组。null，是新增或修改，不是null是删除
        List<Sku> insertOrUpdateList = new ArrayList<>();
        List<Sku> deleteSkuList = new ArrayList<>();
        for (SkuDTO skuDTO : skuDTOList) {
            if (skuDTO.getSaleable() == null){
                insertOrUpdateList.add(skuDTO.toEntity(Sku.class));
            }else {
                deleteSkuList.add(skuDTO.toEntity(Sku.class));
            }
        }
        // 3.3.获取要新增或修改的sku
        if (!CollectionUtils.isEmpty(insertOrUpdateList)){
            skuService.saveOrUpdateBatch(insertOrUpdateList);
        }

        // 3.4.获取要删除的sku
        if (!CollectionUtils.isEmpty(deleteSkuList)){
            List<Long> deleteSkuIds = new ArrayList<>();
            for (Sku sku : deleteSkuList) {
                deleteSkuIds.add(sku.getId());
            }
            skuService.removeByIds(deleteSkuIds);
        }

        // TODO   stream方式   //类::实例方法名 获取类里面的一个实例    实例对象->另外一个实例对象 转化为新的
//        // 3.2.转换DTO，并将sku根据saleable是否为null来分组。null，是新增或修改，不是null是删除
//        Map<Boolean, List<Sku>> map = skuDTOList.stream()
//                .map(skuDTO -> skuDTO.toEntity(Sku.class))
//                .collect(Collectors.groupingBy(sku -> sku.getSaleable() == null));
//
//        // 3.3.获取要新增或修改的sku
//        List<Sku> insertOrUpdateList = map.get(true);
//        // 如果不为空，则修改或新增
//        if(!CollectionUtils.isEmpty(insertOrUpdateList)) {
//            skuService.saveOrUpdateBatch(insertOrUpdateList);
//        }
//
//        // 3.4.获取要删除的sku
//        List<Sku> deleteSkuList = map.get(false);
//        if(!CollectionUtils.isEmpty(deleteSkuList)){
//            // 存在要删除的sku
//            List<Long> idList = deleteSkuList.stream().map(Sku::getId).collect(Collectors.toList());
//            // 删除
//            skuService.removeByIds(idList);
//        }

    }

    @Override
    public SpuDTO querySpuById(Long id) {
        return new SpuDTO(this.getById(id));
    }

    @Override
    public SpuDTO queryGoodsById(Long id) {
        //1.获取spu基本信息
        Spu spu = this.getById(id);
        if (spu == null) {
            throw new LyException(400, "商品id不存在！");
        }
        SpuDTO spuDTO = new SpuDTO(spu);
        //2.获取spu详情
        SpuDetail spuDetail = spuDetailService.getById(id);
        spuDTO.setSpuDetail(new SpuDetailDTO(spuDetail));
        //3.获取sku信息
        List<Sku> skuList = skuService.query().eq("spu_id", id).list();
        spuDTO.setSkus(SkuDTO.convertEntityList(skuList));
        // 4.准备商品分类和品牌名称
        handleCategoryAndBrandName(spuDTO);
        return spuDTO;
    }

    private void handleCategoryAndBrandName(SpuDTO spuDTO) {

        // 查询spu的品牌的名称
        Brand brand = brandService.getById(spuDTO.getBrandId());
        if (brand != null){
            spuDTO.setBrandName(brand.getName());
        }
        // 查询spu的分类
        List<Category> categorieList = categoryService.listByIds(spuDTO.getCategoryIds());
        //StringUtils.join(array,分隔符)
        //拼接字符串
        if (!CollectionUtils.isEmpty(categorieList)){
            // 取出分类的名称，拼接起来
            String names = categorieList.stream()
                    .map(Category::getName)
                    .collect(Collectors.joining("/"));
            spuDTO.setCategoryName(names);
        }
    }
}
